﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
using FIFP.DashBoard.Model;
using FIFP.DashBoard.Helper;

namespace FIFP.DashBoard.Calculation
{


    //Capacity : it means the capacity of each Unit, well's capacity is the capacity of child strings; tower's capacity is the capacity of child wells
    //EffectiveCapacity : it only used for tower/pipeline/radial. tower's EC means the tower's capacity plus all other children's capacity
    //                    pipeline's EC means the minimum of its own capacity and its children's EffectiveCapacity
    //Real Capacity : real capacity on specific day
    public class NewCalculation
    {
        #region Properties
        //Input : All units/facilities
        private List<Unit> allUnitList = new List<Unit>();
        public List<Unit> AllUnitList
        {
            get { return allUnitList; }
            set { allUnitList = value; }
        }

        //Input : shut down plans + link sd
        private List<FIFPAppointment> importScenarioPlans = new List<FIFPAppointment>();
        public List<FIFPAppointment> ImportScenarioPlans
        {
            get { return importScenarioPlans; }
            set { importScenarioPlans = value; }
        }

        //key : unitID
        //value : list of FIFPAppointment including normal shutdown and linked shutdown
        private Dictionary<int, List<FIFPAppointment>> unitShutdownPlanDictionary = new Dictionary<int, List<FIFPAppointment>>();
        public Dictionary<int, List<FIFPAppointment>> UnitShutdownPlanDictionary
        {
            get { return unitShutdownPlanDictionary; }
            set { unitShutdownPlanDictionary = value; }
        }

        //Input : string capacity
        //key:     UnitID.toString()+CurrentDate.toString()
        //value:   Capacity(in the CurrentDate)
        private Dictionary<string, double> unitCapacityDictionary = new Dictionary<string, double>();
        public Dictionary<string, double> UnitCapacityDictionary
        {
            get { return unitCapacityDictionary; }
            set { unitCapacityDictionary = value; }
        }

        //Input : unit layer relationship
        private Dictionary<string, List<UnitLayer>> layerUnitsDictionary = new Dictionary<string, List<UnitLayer>>();
        public Dictionary<string, List<UnitLayer>> LayerUnitsDictionary
        {
            get { return layerUnitsDictionary; }
            set { layerUnitsDictionary = value; }
        }

        //Input : Reduced capacity List
        private List<ReducedCapacity> reducedCapacityList = new List<ReducedCapacity>();
        public List<ReducedCapacity> ReducedCapacityList
        {
            get { return reducedCapacityList; }
            set { reducedCapacityList = value; }
        }

        //Input : default radial List to bypass
        //private List<Unit> byPassRadialList = new List<Unit>();
        //public List<Unit> ByPassRadialList
        //{
        //    get { return byPassRadialList; }
        //    set { byPassRadialList = value; }
        //}
        //Input : default radial List to bypass
        private List<int> defaultByPassRadiaIdList = new List<int>();
        public List<int> DefaultByPassRadialIdList
        {
            get { return defaultByPassRadiaIdList; }
            set { defaultByPassRadiaIdList = value; }
        }

        //Input : Switched Radial List
        private List<RadialSwitch> radialSwitchList = new List<RadialSwitch>();
        public List<RadialSwitch> RadialSwitchList
        {
            get { return radialSwitchList; }
            set { radialSwitchList = value; }
        }

        private SettingsData fieldData = new SettingsData();
        public SettingsData FieldData
        {
            get { return fieldData; }
            set { fieldData = value; }
        }

        ////Input : default radial List to USOSSP
        //private List<int> usosspRadialList = new List<int>();
        //public List<int> UsosspRadialList
        //{
        //    get { return usosspRadialList; }
        //    set { usosspRadialList = value; }
        //}
        #endregion

        #region Units for calculation
        public Unit units_WIP;
        public Unit units_CP1;
        public Unit units_USOSSP;
        public Unit units_ByPass;
        public List<Unit> units_WaterModuleList;
        public List<Unit> units_WaterStringList;
        public List<Unit> units_WaterRadialList;
        public List<Unit> units_GasCompressorList;
        public List<Unit> units_GasTowerList;
        public List<Unit> units_GasAutoInjectionTowerList;
        public List<Unit> units_GasRadialList;
        public List<Unit> units_OilStringList;
        public List<Unit> units_OilRadialList;
        public List<Unit> units_SeparatorList;
        public List<Unit> units_CSPSeparatorList;
        public List<Unit> units_CSP1SeparatorList;

        #endregion

        #region Constructor
        public NewCalculation()
        {
            //allUnitList = new List<Unit>();            
        }


        #endregion

        #region Reservoir Current month Oil Capacity

        public double CalculateCurrentDayTotalOilCapacity(DateTime currentDay)
        {
            double currentDayOilCapacity = 0;
            foreach (Unit oilString in units_OilStringList)
            {
                double strCapacity = getCurrentDayStringCapacity(oilString, currentDay);
                currentDayOilCapacity += strCapacity;
            }
            return currentDayOilCapacity;
        }
        #endregion

        #region Reservoir Capacity Calculation

        /// <summary>
        /// get the sum of all oil string to calculate reservoir capacity
        /// </summary>
        /// <param name="currentMonth"></param>
        /// <returns>reservoir capacity for the input month</returns>
        public double CalculateCurrentMonthReservoirCapacity(DateTime currentMonth)
        {
            int numberOfDays = DateTime.DaysInMonth(currentMonth.Year, currentMonth.Month);

            double currentMonthReservoirCapacity = 0;
            foreach (Unit u in units_OilStringList)
            {
                string key = getKeyForStringCapacity(u.UnitID, currentMonth);
                if (unitCapacityDictionary.ContainsKey(key))
                    currentMonthReservoirCapacity += unitCapacityDictionary[key] * numberOfDays;
            }
            return currentMonthReservoirCapacity;
        }
        #endregion

        #region Effective Capacity Calculation

        public double CalculateCurrentDayEffectiveCapacity(DateTime currentDay)
        {
            foreach (Unit tu in allUnitList)
            {
                tu.EffectiveCapacity = 0;
                tu.RealCapacity = 0;
                tu.IsBottleNeck = false;

                if (tu.UnitType == FIFPConstants.UNITTYPE_TOWER || tu.UnitType == FIFPConstants.UNITTYPE_WELL || tu.UnitType == FIFPConstants.UNITTYPE_STRING)
                    tu.Capacity = 0;
            }

            CalculateWaterStringCurrentDayRealCapacity(currentDay);
            CalculateGasWellCurrentDayRealCapacity(currentDay);
            return CalculateOilNetworkCurrentDayEffectiveCapacity(currentDay);
        }

        #region Water Network Real capacity calculation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentDay"></param>
        private void CalculateWaterStringCurrentDayRealCapacity(DateTime currentDay)
        {
            //water facility sum capacity
            double sumWaterFacilityCapacity = getCurrentDayWaterFacilityCapacity(currentDay);
            if (sumWaterFacilityCapacity == 0)
            {
                setRealCapacityAsZerotoAllWaterStrings();
                return;
            }
            //calculate water radial sum capacity 
            double sumWaterRadialEffectiveCapacity = getCurrentDayWaterRadialSumEC(currentDay, units_WaterRadialList);
            if (sumWaterRadialEffectiveCapacity == 0)
            {
                setRealCapacityAsZerotoAllWaterStrings();
            }
            else
            {   //calculate the real capacity for each water string (radial,pipeline)
                if (sumWaterFacilityCapacity < sumWaterRadialEffectiveCapacity)
                {
                    foreach (Unit wr in units_WaterRadialList)
                    {
                        wr.RealCapacity = double.IsNaN(wr.EffectiveCapacity / sumWaterRadialEffectiveCapacity) ? 0 : (wr.EffectiveCapacity / sumWaterRadialEffectiveCapacity) * sumWaterFacilityCapacity;
                        DistributeFromWaterRadialtoString(wr);
                    }
                }
                else
                {
                    foreach (Unit wr in units_WaterRadialList)
                    {
                        wr.RealCapacity = wr.EffectiveCapacity;
                        DistributeFromWaterRadialtoString(wr);
                    }
                }
            }
        }

        private double getCurrentDayWaterFacilityCapacity(DateTime currentDay)
        {
            double currentDayWIPCapacity = getCurrentDayWIPCapacity(currentDay);
            double currentDayWaterModuleSumCapacity = getCurrentDayWaterModuleSumCapacity(currentDay, units_WaterModuleList);
            if (currentDayWIPCapacity == 0 || currentDayWaterModuleSumCapacity == 0)
                return 0;
            else
                return Math.Min(currentDayWIPCapacity, currentDayWaterModuleSumCapacity);
        }

        private double getCurrentDayWIPCapacity(DateTime currentDay)
        {
            if (units_WIP.UnitID == 1150 && currentDay.Day == 2 && currentDay.Month == 1 && currentDay.Year == 2013)
            {
                string str = "test";
            }
            double result = 0;
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(units_WIP, currentDay, rHelper) == true)
            {
                if (rHelper.ReducedCapacity == 0)
                    result = 0;
                else
                    result = units_WIP.Capacity - rHelper.ReducedCapacity;
            }
            else
            {
                result = units_WIP.Capacity;
            }
            return result;
        }

        private double getCurrentDayWaterModuleSumCapacity(DateTime currentDay, List<Unit> waterModuleList)
        {
            double sumWaterModuleCapacity = 0;
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            foreach (Unit wm in waterModuleList)
            {
                //if water module is not shutdown
                if (isUnitShutdown(wm, currentDay, rHelper) == false)
                {
                    sumWaterModuleCapacity += wm.Capacity;
                    wm.RealCapacity = wm.Capacity;
                }
                else
                {
                    if (rHelper.ReducedCapacity == 0)
                    {
                        wm.RealCapacity = 0;
                    }
                    else
                    {
                        wm.RealCapacity = wm.Capacity - rHelper.ReducedCapacity;
                    }
                    sumWaterModuleCapacity += wm.RealCapacity;
                }
            }
            return sumWaterModuleCapacity;
        }

        private void setRealCapacityAsZerotoAllWaterStrings()
        {
            foreach (Unit ws in units_WaterStringList)
            {
                ws.RealCapacity = 0;
            }
        }

        /// <summary>
        /// calculate the sum of effective capacity for every water radial at currentday
        /// </summary>
        /// <param name="currentDay"></param>
        /// <param name="waterRadialList"></param>
        /// <returns></returns>
        private double getCurrentDayWaterRadialSumEC(DateTime currentDay, List<Unit> waterRadialList)
        {
            double sumWaterRadialEffectiveCapacity = 0;
            foreach (Unit wr in waterRadialList)
            {
                WaterNodeEffectiveCapacityCalculation(wr, currentDay);
                sumWaterRadialEffectiveCapacity += wr.EffectiveCapacity;
            }
            return sumWaterRadialEffectiveCapacity;
        }

        /// <summary>
        /// recursively calculate effective capacity for one water radial at currentday
        /// the algrithrom considers partial shutdown
        /// </summary>
        /// <param name="node"></param>
        /// <param name="currentDay"></param>
        private void WaterNodeEffectiveCapacityCalculation(Unit node, DateTime currentDay)
        {
            if (isLeafNode(node))
            {
                List<Unit> waterWells = (from item in node.ChildUnitList
                                         where item.FluidType == FIFPConstants.FLUIDTYPE_WATER
                                         select item).ToList<Unit>();
                foreach (Unit well in waterWells)
                {
                    setCurrentDayWellAndStringCapacity(well, currentDay);
                    node.EffectiveCapacity += well.Capacity;
                    node.Capacity += well.Capacity;
                }
            }
            else
            {
                if (node.UnitType == FIFPConstants.UNITTYPE_TOWER)
                {
                    List<Unit> notWellChildren = getChildWithoutWells(node);
                    foreach (Unit child in notWellChildren)
                    {
                        //recursively calculate child EC
                        WaterNodeEffectiveCapacityCalculation(child, currentDay);
                        //add child EC to tower EC
                        node.EffectiveCapacity += child.EffectiveCapacity;
                    }

                    List<Unit> wells = getChildWaterWells(node);
                    foreach (Unit well in wells)
                    {
                        setCurrentDayWellAndStringCapacity(well, currentDay);
                        node.EffectiveCapacity += well.Capacity;
                        node.Capacity += well.Capacity;
                    }
                }
                else if (node.UnitType == FIFPConstants.UNITTYPE_RADIAL || node.UnitType == FIFPConstants.UNITTYPE_PIPELINE)
                {
                    List<Unit> children = node.ChildUnitList;
                    double childrenEffectiveCapacity = 0;
                    if (children != null)
                    {
                        foreach (Unit child in children)
                        {
                            //recursively calculate child EC
                            WaterNodeEffectiveCapacityCalculation(child, currentDay);
                            childrenEffectiveCapacity += child.EffectiveCapacity;
                        }
                    }

                    ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                    if (isUnitShutdown(node, currentDay, rHelper))
                    {
                        if (rHelper.ReducedCapacity != 0)
                        {
                            double currentDayCapacity = node.Capacity - rHelper.ReducedCapacity;
                            node.EffectiveCapacity = Math.Min(currentDayCapacity, childrenEffectiveCapacity);
                        }
                        else
                            node.EffectiveCapacity = 0;
                        //node.IsBottleNeck = true;
                    }
                    else
                    {
                        //pipeline capacity not big enough, maybe caused by pipeline partial shutdown
                        node.EffectiveCapacity = Math.Min(node.Capacity, childrenEffectiveCapacity);
                        //if (node.Capacity < childrenEffectiveCapacity)
                        //    node.IsBottleNeck = true;
                    }
                }
            }
        }

        /// <summary>
        /// distribute water(real capacity) from radial to the below level,
        /// considering partial shutdown
        /// </summary>
        /// <param name="node"></param>
        private void DistributeFromWaterRadialtoString(Unit node)
        {
            List<Unit> children = node.ChildUnitList;

            double sumEffectiveCapacityForChildren = 0;
            foreach (Unit u in children)
            {
                sumEffectiveCapacityForChildren += u.EffectiveCapacity;
            }

            foreach (Unit u in children)
            {
                if (sumEffectiveCapacityForChildren == 0)
                    u.RealCapacity = 0;
                else
                    u.RealCapacity = double.IsNaN(u.EffectiveCapacity / sumEffectiveCapacityForChildren) ? 0 : (u.EffectiveCapacity / sumEffectiveCapacityForChildren) * node.RealCapacity;

                //assume only tower connected to radial or pipeline   
                if (u.UnitType == FIFPConstants.UNITTYPE_TOWER)
                {
                    List<Unit> allChildren = u.ChildUnitList;
                    List<Unit> allWells = getChildWells(u);
                    List<Unit> allWaterWells = getChildWaterWells(u);

                    //if it is leaf tower
                    if (allChildren.Count == allWells.Count)
                    {
                        double tempSumValue = 0;
                        foreach (Unit w in allWaterWells)
                        {
                            tempSumValue += w.Capacity;
                        }

                        foreach (Unit w in allWaterWells)
                        {
                            if (tempSumValue == 0)
                                w.RealCapacity = 0;
                            else
                                w.RealCapacity = double.IsNaN(w.Capacity / tempSumValue) ? 0 : (w.Capacity / tempSumValue) * u.RealCapacity;
                            DistributeFromWelltoString(w);
                        }
                    }
                    //if it is not leaf tower
                    else
                    {
                        double tempSumValue = 0;
                        foreach (Unit w in allChildren)
                        {
                            if (w.UnitType == FIFPConstants.UNITTYPE_WELL)
                                tempSumValue += w.Capacity;
                            else if (w.UnitType == FIFPConstants.UNITTYPE_PIPELINE)
                                tempSumValue += w.EffectiveCapacity;
                        }

                        foreach (Unit c in allChildren)
                        {
                            if (c.UnitType == FIFPConstants.UNITTYPE_WELL)
                            {
                                if (tempSumValue == 0)
                                    c.RealCapacity = 0;
                                else
                                    c.RealCapacity = double.IsNaN(c.Capacity / tempSumValue) ? 0 : (c.Capacity / tempSumValue) * u.RealCapacity;
                                DistributeFromWelltoString(c);
                            }
                            else if (c.UnitType == FIFPConstants.UNITTYPE_PIPELINE)
                            {
                                if (tempSumValue == 0)
                                    c.RealCapacity = 0;
                                else
                                    c.RealCapacity = double.IsNaN(c.EffectiveCapacity / tempSumValue) ? 0 : (c.EffectiveCapacity / tempSumValue) * u.RealCapacity;
                            }
                        }

                        foreach (Unit p in allChildren)
                        {
                            if (p.UnitType == FIFPConstants.UNITTYPE_PIPELINE)
                            {
                                DistributeFromWaterRadialtoString(p);
                            }
                        }
                    }
                }
            }
        }

        private void DistributeFromWelltoString(Unit well)
        {
            if (well.RealCapacity == 0)
            {
                foreach (Unit s in well.ChildUnitList)
                {
                    s.RealCapacity = 0;
                }
                return;
            }

            double tempSumValue = 0;
            foreach (Unit s in well.ChildUnitList)
            {
                tempSumValue += s.Capacity;
            }

            if (tempSumValue == 0)
            {
                foreach (Unit s in well.ChildUnitList)
                {
                    s.RealCapacity = 0;
                }
            }
            else
            {
                foreach (Unit s in well.ChildUnitList)
                {
                    s.RealCapacity = double.IsNaN(s.Capacity / tempSumValue) ? 0 : (s.Capacity / tempSumValue) * well.RealCapacity;
                }
            }
        }

        #endregion

        #region Gas well Real capacity calculation
        private void CalculateGasWellCurrentDayRealCapacity(DateTime currentDay)
        {
            //gas facility sum facility
            double sumGasFacilityCapacity = getCurrentDayGasFacilityCapacity(currentDay);
            //
            List<Unit> autoInjectionTowerList = units_GasAutoInjectionTowerList;
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(units_CP1, currentDay, rHelper) == true)
            {
                autoInjectionTowerList = units_GasTowerList;
            }
            else
            {
                //GIF gas radial sum effective capacity 
                double sumGasRadialEffectiveCapacity = getCurrentDayGasRadialSumEC(currentDay, units_GasRadialList);
                if (sumGasRadialEffectiveCapacity == 0)
                {
                    setGIFGasWellRealCapacityZero(units_GasRadialList);
                }
                else
                {
                    if (sumGasFacilityCapacity < sumGasRadialEffectiveCapacity)
                    {
                        foreach (Unit gr in units_GasRadialList)
                        {
                            gr.RealCapacity = double.IsNaN(gr.EffectiveCapacity / sumGasRadialEffectiveCapacity) ? 0 : (gr.EffectiveCapacity / sumGasRadialEffectiveCapacity) * sumGasFacilityCapacity;
                            DistributeFromGasRadialtoWell(gr);
                            //Unit u = gr.ChildUnitList[0];
                            //List<Unit> wells = (from item in u.ChildUnitList
                            //                    where item.ProdInjType == "I"
                            //                    select item).ToList<Unit>();

                            //foreach (Unit w in wells)
                            //{
                            //    string s = w.RealCapacity.ToString() + w.UnitName;
                            //}
                        }
                    }
                    else
                    {
                        foreach (Unit gr in units_GasRadialList)
                        {
                            gr.RealCapacity = gr.EffectiveCapacity;
                            DistributeFromGasRadialtoWell(gr);
                        }
                    }
                }
            }

            //add auto injection gas well real capacity calculation
            foreach (Unit t in autoInjectionTowerList)
            {
                List<Unit> gasInjectionWellList = (from item in t.ChildUnitList
                                                   where item.ProdInjType == "I"
                                                   select item).ToList<Unit>();

                foreach (Unit w in gasInjectionWellList)
                {
                    w.RealCapacity = getCurrentDayGasWellCapacity(w, currentDay);
                }
            }

        }

        private void setGIFGasWellRealCapacityZero(List<Unit> gasRadialList)
        {
            foreach (Unit radial in gasRadialList)
            {
                foreach (Unit tower in radial.ChildUnitList)
                {
                    foreach (Unit well in tower.ChildUnitList)
                    {
                        well.RealCapacity = 0;
                    }
                }
            }
        }

        private double getCurrentDayGasFacilityCapacity(DateTime currentDay)
        {
            double currentDayCP1Capacity = getCurrentDayCP1Capacity(currentDay);
            double sumGasCompressorCapacity = getCurrentDayGasCompressorSumCapacity(currentDay, units_GasCompressorList);
            if (currentDayCP1Capacity == 0 || sumGasCompressorCapacity == 0)
                return 0;
            else
                return Math.Min(currentDayCP1Capacity, sumGasCompressorCapacity);
        }

        private double getCurrentDayCP1Capacity(DateTime currentDay)
        {
            double result = 0;
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(units_CP1, currentDay, rHelper) == true)
            {
                if (rHelper.ReducedCapacity == 0)
                    result = 0;
                else
                    result = units_CP1.Capacity - rHelper.ReducedCapacity;
            }
            else
            {
                result = units_CP1.Capacity;
            }
            return result;
        }

        private double getCurrentDayGasCompressorSumCapacity(DateTime currentDay, List<Unit> gasCompressorList)
        {
            double sumGasCompressorCapacity = 0;
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            foreach (Unit gc in gasCompressorList)
            {
                if (isUnitShutdown(gc, currentDay, rHelper) == false)
                {
                    sumGasCompressorCapacity += gc.Capacity;
                    gc.RealCapacity = gc.Capacity;
                }
                else
                {
                    if (rHelper.ReducedCapacity != 0)
                        gc.RealCapacity = gc.Capacity - rHelper.ReducedCapacity;
                    else
                        gc.RealCapacity = 0;
                }
            }
            return sumGasCompressorCapacity;
        }

        private double getCurrentDayGasRadialSumEC(DateTime currentDay, List<Unit> gasRadialList)
        {
            double sumGasRadialEffectiveCapacity = 0;
            foreach (Unit gr in gasRadialList)
            {
                GasNodeEffectiveCapacityCalculation(gr, currentDay);
                sumGasRadialEffectiveCapacity += gr.EffectiveCapacity;
            }
            return sumGasRadialEffectiveCapacity;
        }

        private void GasNodeEffectiveCapacityCalculation(Unit node, DateTime currentDay)
        {
            if (isLeafNode(node))
            {
                List<Unit> wells = (from item in node.ChildUnitList
                                    where item.ProdInjType == "I"
                                    select item).ToList<Unit>();
                foreach (Unit well in wells)
                {
                    well.Capacity = getCurrentDayGasWellCapacity(well, currentDay);
                    node.EffectiveCapacity += well.Capacity;
                    node.Capacity += well.Capacity;
                }
            }
            else
            {
                if (node.UnitType == FIFPConstants.UNITTYPE_TOWER)
                {
                    List<Unit> notWellChildren = getChildWithoutWells(node);
                    foreach (Unit child in notWellChildren)
                    {
                        //recursively calculate child EC
                        GasNodeEffectiveCapacityCalculation(child, currentDay);
                        //add child EC to tower EC
                        node.EffectiveCapacity += child.EffectiveCapacity;
                    }

                    List<Unit> wells = getChildGasInjectionWells(node);
                    foreach (Unit well in wells)
                    {
                        setCurrentDayWellAndStringCapacity(well, currentDay);
                        //add well EC to tower EC
                        node.EffectiveCapacity += well.Capacity;
                        //add well C to tower C
                        node.Capacity += well.Capacity;
                    }
                }
                else if (node.UnitType == FIFPConstants.UNITTYPE_RADIAL || node.UnitType == FIFPConstants.UNITTYPE_PIPELINE)
                {
                    List<Unit> children = node.ChildUnitList;
                    double childrenEffectiveCapacity = 0;
                    if (children != null)
                    {
                        foreach (Unit child in children)
                        {
                            //recursively calculate child EC
                            GasNodeEffectiveCapacityCalculation(child, currentDay);
                            childrenEffectiveCapacity += child.EffectiveCapacity;
                        }
                    }
                    //pipeline capacity not big enough, maybe caused by pipeline partial shutdown
                    ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                    if (isUnitShutdown(node, currentDay, rHelper))
                    {
                        if (rHelper.ReducedCapacity == 0)
                            node.EffectiveCapacity = 0;
                        else
                        {
                            double currentDayCapacity = node.Capacity - rHelper.ReducedCapacity;
                            node.EffectiveCapacity = Math.Min(currentDayCapacity, childrenEffectiveCapacity);
                        }
                    }
                    else
                    {
                        node.EffectiveCapacity = Math.Min(node.Capacity, childrenEffectiveCapacity);
                    }
                }
            }
        }

        private void DistributeFromGasRadialtoWell(Unit radial)
        {
            //according to current gas structure,  only 1 tower connected to radial    
            List<Unit> children = radial.ChildUnitList;

            if (children != null && children.Count > 0)
            {
                Unit tower = children[0];
                tower.RealCapacity = radial.RealCapacity;

                List<Unit> wells = (from item in tower.ChildUnitList
                                    where item.ProdInjType == "I"
                                    select item).ToList<Unit>();
                double tempSumValue = 0;
                foreach (Unit w in wells)
                {
                    tempSumValue += w.Capacity;
                }
                foreach (Unit w in wells)
                {
                    if (tempSumValue == 0)
                        w.RealCapacity = 0;
                    else
                    {
                        w.RealCapacity = double.IsNaN((w.Capacity / tempSumValue)) ? 0 : (w.Capacity / tempSumValue) * tower.RealCapacity;
                        //transfer unit from gas to water
                        //w.RealCapacity = w.RealCapacity / ?;
                    }
                }
            }
        }

        #endregion

        #region Oil Network effective capacity Calculation
        private double CalculateOilNetworkCurrentDayEffectiveCapacity(DateTime currentDay)
        {
            //set currentday oil capacity
            SetOilStringCapacityAfterApplyShutdown(currentDay);
            //set currentday oil string real capacity
            CalculateOilStringCurrentDayRealCapacityByLayerInjectionCompare(currentDay);

            List<Unit> oilRadialList = getOilRadials();
            //calculate tower with multiple radial effective capacity
            List<Unit> towerWithMultipleRadials = (from item in allUnitList
                                                   where item.UnitType == FIFPConstants.UNITTYPE_TOWER
                                                   && item.hasMultipleParent == true
                                                   select item).ToList<Unit>();
            foreach (Unit tower in towerWithMultipleRadials)
            {
                List<int> pIds = tower.ParentUnitIDList; //example calculation : 32,33(UOR-36)
                OilNodeEffectiveCapacityCalculation(tower, currentDay);//UT-36

                double sumParentRadialCapacity = 0;
                foreach (int pId in pIds)
                {
                    Unit r = getUnitByUID(pId);
                    tower.ParentUnitList.Add(r);
                    oilRadialList.Remove(r);

                    //get current day radial capacity
                    ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                    if (isUnitShutdown(r, currentDay, rHelper))
                    {
                        if (rHelper.ReducedCapacity == 0)
                            r.EffectiveCapacity = 0;
                        else
                        {
                            double currentDayCapacity = r.Capacity - rHelper.ReducedCapacity;
                            r.EffectiveCapacity = currentDayCapacity;
                        }
                    }
                    else
                    {
                        r.EffectiveCapacity = r.Capacity;
                    }
                    sumParentRadialCapacity += r.EffectiveCapacity;
                }
                //               
                foreach (Unit r in tower.ParentUnitList)
                {
                    r.EffectiveCapacity = double.IsNaN((r.EffectiveCapacity / sumParentRadialCapacity)) ? 0 : ((r.EffectiveCapacity / sumParentRadialCapacity) * tower.EffectiveCapacity);
                }

            }
            //calculate normal radial effective capacity
            foreach (Unit oilRadial in oilRadialList)
            {
                OilNodeEffectiveCapacityCalculation(oilRadial, currentDay);
            }
            //HashSet<Unit> radialPlatforms = new HashSet<Unit>();
            return CalculateOilNetworkEffectiveCapacityHardCode(currentDay, units_OilRadialList);
            //CalculateOilNetworkEffectiveCapacity(radialPlatforms.ToList<Unit>());
        }

        /// <summary>
        /// set oil string capacity consider shutdown, if shutdown, capacity is zero
        /// </summary>
        /// <param name="currentDay"></param>
        private void SetOilStringCapacityAfterApplyShutdown(DateTime currentDay)
        {
            foreach (Unit oilString in units_OilStringList)
            {                
                double strCapacity = getCurrentDayStringCapacity(oilString, currentDay);
                oilString.Capacity = strCapacity;
            }
        }

        /// <summary>
        ///  compare injection and production in each layer, and set oil string real capacity
        /// </summary>
        /// <param name="currentDay"></param>
        private double CalculateOilStringCurrentDayRealCapacityByLayerInjectionCompare(DateTime currentDay)
        {
            List<string> layerNameList = layerUnitsDictionary.Keys.ToList<string>();
            List<Unit> layerProductorList = new List<Unit>();
            double sumLayerInjectorCapacity = 0;
            double sumLayerProductorCapacity = 0;
            List<Unit> injectorWaterList = new List<Unit>();
            List<Unit> injectorGasList = new List<Unit>();

            double sumNonArabOilStringRealCapacity = 0;

            foreach (string layerName in layerNameList)
            {
                //List<UnitLayer> ulList = new List<UnitLayer>();
                //non arab layer producers real capacity
                if (layerName.Contains("NOT ARAB"))
                {
                    List<UnitLayer> ulList = layerUnitsDictionary[layerName];
                    foreach (UnitLayer ul in ulList)
                    {
                        Unit u = getUnitByUID(ul.unitID);
                        u.RealCapacity = u.Capacity;
                        sumNonArabOilStringRealCapacity = u.RealCapacity;
                    }
                }
                else
                {
                    List<UnitLayer> ulList = layerUnitsDictionary[layerName];

                    foreach (UnitLayer ul in ulList)
                    {
                        Unit u = getUnitByUID(ul.unitID);                       

                        if (u == null)
                            continue;

                        //each producer belongs to only one layer
                        if (u.FluidType == FIFPConstants.FLUIDTYPE_OIL)
                        {
                            layerProductorList.Add(u);
                            sumLayerProductorCapacity += u.Capacity * ul.percentage;
                        }
                        else if (u.FluidType == FIFPConstants.FLUIDTYPE_WATER)
                        {
                           
                            //unit transfer from MBWD(water unit) to  MBOD(oil unit) ?
                            sumLayerInjectorCapacity += u.RealCapacity * ul.percentage;
                            injectorWaterList.Add(u);
                        }
                        else if (u.FluidType == FIFPConstants.FLUIDTYPE_GAS)
                        {
                            //unit transfer from MMSCFD(gas unit) to MBOD(oil unit)
                            //sumLayerInjectorCapacity += u.RealCapacity * ul.percentage * 0.6298 * 0.5;
                            sumLayerInjectorCapacity += u.RealCapacity * ul.percentage * 0.73;
                            injectorGasList.Add(u);
                        }
                    }

                  
                    if (layerProductorList.Count == 0)
                        continue;
                    //later need to apply layer IPR
                    //double IPR = 1.85; 
                    double IPR = 1.85; //Get admin setings ipr value from database
                    if (ulList != null && ulList.Count > 0)
                        IPR = ulList[0].IPR;
                    //layer injection and production compare
                    //pre : Each production string only in one layer
                    double InjectionAfterApplyIPR = double.IsNaN(sumLayerInjectorCapacity / IPR) ? 0 : sumLayerInjectorCapacity / IPR;
                    if (sumLayerProductorCapacity < InjectionAfterApplyIPR)
                    {
                        foreach (Unit productor in layerProductorList)
                        {
                            productor.RealCapacity = productor.Capacity;
                        }
                    }
                    else
                    {
                        foreach (Unit productor in layerProductorList)
                        {
                            productor.RealCapacity = double.IsNaN((productor.Capacity / sumLayerProductorCapacity) * InjectionAfterApplyIPR) ? 0 : (productor.Capacity / sumLayerProductorCapacity) * InjectionAfterApplyIPR;
                        }
                    }

                    sumLayerInjectorCapacity = 0;
                    sumLayerProductorCapacity = 0;
                    layerProductorList.Clear();
                    //injectorList.Clear();
                }
            }
            return sumNonArabOilStringRealCapacity;
        }

        private void OilNodeEffectiveCapacityCalculation(Unit node, DateTime currentDay)
        {
            if (isLeafNode(node))
            {
                List<Unit> wells = node.ChildUnitList;
                foreach (Unit well in wells)
                {
                    setCurrentDayOilWellCapacity(well, currentDay);
                    node.EffectiveCapacity += well.Capacity;
                    node.Capacity += well.Capacity;
                }
            }
            else
            {
                if (node.UnitType == FIFPConstants.UNITTYPE_TOWER)
                {
                    List<Unit> notWellChildren = getChildWithoutWells(node);
                    foreach (Unit child in notWellChildren)
                    {
                        //recursively calculate child EC
                        OilNodeEffectiveCapacityCalculation(child, currentDay);
                        //add child EC to tower EC
                        node.EffectiveCapacity += child.EffectiveCapacity;
                    }

                    List<Unit> wells = getChildOilWells(node);
                    foreach (Unit well in wells)
                    {
                        setCurrentDayOilWellCapacity(well, currentDay);
                        //add well EC to tower EC
                        node.EffectiveCapacity += well.Capacity;
                        //add well C to tower C
                        node.Capacity += well.Capacity;
                    }
                }
                else if (node.UnitType == FIFPConstants.UNITTYPE_RADIAL || node.UnitType == FIFPConstants.UNITTYPE_PIPELINE)
                {
                    if (node.UnitName == "UOR-12" && currentDay.Day == 13 && currentDay.Month == 1 && currentDay.Year == 2013)
                    {
                        string str = "test";
                    }
                    List<Unit> children = node.ChildUnitList;
                    double childrenEffectiveCapacity = 0;
                    foreach (Unit child in children)
                    {
                        //recursively calculate child EC
                        OilNodeEffectiveCapacityCalculation(child, currentDay);
                        childrenEffectiveCapacity += child.EffectiveCapacity;
                    }

                    ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                    if (isUnitShutdown(node, currentDay, rHelper))
                    {
                        if (rHelper.ReducedCapacity == 0)
                            node.EffectiveCapacity = 0;
                        else
                        {
                            double currentDayCapacity = node.Capacity - rHelper.ReducedCapacity;
                            node.EffectiveCapacity = Math.Min(currentDayCapacity, childrenEffectiveCapacity);
                        }
                        //node.IsBottleNeck = true;
                    }
                    else
                    {
                        //pipeline capacity not big enough, maybe caused by pipeline partial shutdown
                        node.EffectiveCapacity = Math.Min(node.Capacity, childrenEffectiveCapacity);
                        //if (node.Capacity < childrenEffectiveCapacity)
                        //node.IsBottleNeck = true;
                    }
                }
                //else if (node.UnitType == FIFPConstants.UNITTYPE_PLATFORM)
                //{
                //    List<Unit> children = node.ChildUnitList;
                //    foreach (Unit child in children)
                //    {
                //        //recursively calculate child radial EC
                //        OilNodeEffectiveCapacityCalculation(child, currentDay);
                //        node.EffectiveCapacity += child.EffectiveCapacity;
                //    }
                //}
            }
        }

        private void setCurrentDayOilWellCapacity(Unit well, DateTime currentDay)
        {
            double wellCapacity = 0;
            foreach (Unit str in well.ChildUnitList)
            {
                wellCapacity += str.RealCapacity;
            }
            well.Capacity = wellCapacity;
            well.EffectiveCapacity = wellCapacity;
        }

        private double CalculateOilNetworkEffectiveCapacityHardCode(DateTime currentDay, List<Unit> oilRadialList)
        {
            List<Unit> byPassRadialList = getCurrentDayByPassRadialList(currentDay);
            double sumECToByPassOilRadials = 0;
            foreach (Unit r in byPassRadialList)
            {
                sumECToByPassOilRadials += r.EffectiveCapacity;
            }
            double sumECToAllOilRadials = 0;
            foreach (Unit r in oilRadialList)
            {
                sumECToAllOilRadials += r.EffectiveCapacity;
            }
            double byPassEC = Math.Min(sumECToByPassOilRadials, getCurrentDayByPassCapacity(currentDay));
            double usosspEC = Math.Min((sumECToAllOilRadials - sumECToByPassOilRadials), getCurrentDaySeperatorsCapacity(currentDay));
            return Math.Min(byPassEC + usosspEC, getCurrentDayMOLCapacity(currentDay));
        }

        private List<Unit> getCurrentDayByPassRadialList(DateTime currentDay)
        {
            //
            HashSet<int> currentDayByPassRadialIdList = new HashSet<int>();
            foreach (int id in defaultByPassRadiaIdList)
            {
                currentDayByPassRadialIdList.Add(id);
            }
            //
            foreach (RadialSwitch rs in radialSwitchList)
            {
                if (currentDay >= rs.StartDate && currentDay <= rs.EndDate)
                {
                    if (defaultByPassRadiaIdList.Contains(rs.UnitId))
                    {
                        currentDayByPassRadialIdList.Remove(rs.UnitId);
                    }
                    else
                    {
                        currentDayByPassRadialIdList.Add(rs.UnitId);
                    }
                }
            }
            return allUnitList.Where(s => currentDayByPassRadialIdList.Any(p => p.Equals(s.UnitID))).ToList<Unit>();
        }

        private double getCurrentDayByPassCapacity(DateTime currentDay)
        {
            double result = 0;
            if (units_ByPass == null)
                result = 0;
            else
            {
                ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                if (isUnitShutdown(units_ByPass, currentDay, rHelper) == true)
                {
                    if (rHelper.ReducedCapacity == 0)
                        result = 0;
                    else
                        result = units_ByPass.Capacity - rHelper.ReducedCapacity;

                }
                else
                {
                    result = units_ByPass.Capacity;
                }
            }
            return result;
        }

        //private double getCurrentDayOilFacilityCapacity(DateTime currentDay)
        //{
        //    double currentDayUSOSSPCapacity = getCurrentDayUSOSSPCapacity(currentDay);
        //    double currentDaySeparatorSumCapacity = getCurrentDaySeperatorsCapacity(currentDay);
        //    if (currentDayUSOSSPCapacity == 0 || currentDaySeparatorSumCapacity == 0)
        //        return 0;
        //    else
        //        return Math.Min(currentDayUSOSSPCapacity, currentDaySeparatorSumCapacity);
        //}

        private double getCurrentDayUSOSSPCapacity(DateTime currentDay)
        {
            double result = 0;
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(units_USOSSP, currentDay, rHelper) == true)
            {
                if (rHelper.ReducedCapacity == 0)
                    result = 0;
                else
                    result = units_USOSSP.Capacity - rHelper.ReducedCapacity;
            }
            else
            {
                result = units_USOSSP.Capacity;
            }
            return result;
        }

        private double getCurrentDaySeperatorsCapacity(DateTime currentDay)
        {
            double cspResult = 0; double csp1Result = 0;
            foreach (Unit separator in units_CSPSeparatorList)
            {
                ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                if (isUnitShutdown(separator, currentDay, rHelper) == true)
                {
                    if (rHelper.ReducedCapacity == 0)
                        cspResult += 0;
                    else
                        cspResult += (separator.Capacity - rHelper.ReducedCapacity);
                }
                else
                {
                    cspResult += separator.Capacity;
                }
            }

            foreach (Unit separator in units_CSP1SeparatorList)
            {
                ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                if (isUnitShutdown(separator, currentDay, rHelper) == true)
                {
                    if (rHelper.ReducedCapacity == 0)
                        csp1Result += 0;
                    else
                        csp1Result += (separator.Capacity - rHelper.ReducedCapacity);
                }
                else
                {
                    csp1Result += separator.Capacity;
                }
            }

            double cspCapacity = getCurrentDayFacilityCapacityByFacilityName(currentDay, "CSP");
            double csp1Capacity = getCurrentDayFacilityCapacityByFacilityName(currentDay, "CSP-1");
            cspResult = Math.Min(cspCapacity, cspResult);
            csp1Result = Math.Min(csp1Capacity, csp1Result);
            double usosspCapacity = getCurrentDayUSOSSPCapacity(currentDay);
            return Math.Min(cspResult + csp1Result, usosspCapacity);
        }

        private double getCurrentDayFacilityCapacityByFacilityName(DateTime currentDay, string facilityName)
        {
            double result = 0;
            Unit facility = (from item in allUnitList
                             where item.UnitName == facilityName
                             select item).ToList<Unit>()[0];

            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(facility, currentDay, rHelper) == true)
            {
                if (rHelper.ReducedCapacity == 0)
                    result = 0;
                else
                    result = facility.Capacity - rHelper.ReducedCapacity;

            }
            else
            {
                result = facility.Capacity;
            }

            return result;
        }

        private double getCurrentDayMOLCapacity(DateTime currentDay)
        {
            double result = 0;
            Unit bypassline = (from item in allUnitList
                               where item.UnitName == "US MOL"
                               select item).ToList<Unit>()[0];

            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(bypassline, currentDay, rHelper) == true)
            {
                if (rHelper.ReducedCapacity == 0)
                    result = 0;
                else
                    result = bypassline.Capacity - rHelper.ReducedCapacity;

            }
            else
            {
                result = bypassline.Capacity;
            }

            return result;
        }

        /// <summary>
        /// recursively calculate capacity by level
        /// </summary>
        /// <param name="unitList"></param>
        /// <returns></returns>
        private double CalculateOilNetworkEffectiveCapacity(List<Unit> unitList)
        {
            double result = 0;
            double sumCapacity = 0;

            HashSet<int> parentUnitIDSet = new HashSet<int>();
            foreach (Unit unit in unitList)
            {
                // need to change to apply shutdown and get current day capacity
                sumCapacity += unit.Capacity;
                foreach (int id in unit.ParentUnitIDList)
                    parentUnitIDSet.Add(id);
            }

            int rootNode = 0;
            foreach (int i in parentUnitIDSet)
            {
                rootNode += i;
            }

            //check root node
            if (rootNode == -1)
            {
                result = sumCapacity;
            }
            else
            {
                List<Unit> parentList = new List<Unit>();
                foreach (int pId in parentUnitIDSet)
                {
                    Unit unit = getUnitByUID(pId);
                    parentList.Add(unit);
                }
                result = Math.Min(sumCapacity, CalculateOilNetworkEffectiveCapacity(parentList));
            }
            return result;
        }

        #endregion

        #endregion

        #region Loss Calculation
        public List<LossByDivisionAndData> CalculateCurrentDayLossByDivision(DateTime currentDay)
        {


            List<LossByDivisionAndData> result = new List<LossByDivisionAndData>();

            foreach (Unit oilString in units_OilStringList)
            {
                if (unitShutdownPlanDictionary.ContainsKey(oilString.UnitID))
                {
                    List<FIFPAppointment> unitShutDownPlans = unitShutdownPlanDictionary[oilString.UnitID];
                    bool unitIsShutdown = false;
                    FIFPAppointment targetAppointment = null;

                    ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
                    foreach (FIFPAppointment p in unitShutDownPlans)
                    {
                        if (currentDay >= p.Start && currentDay <= p.End)
                        {
                            rHelper.CapacityPercentage = p.CapacityPercentage;
                            //rHelper.ReducedCapacity = getCurrentDayUnitReducedCapacity(oilString, currentDay);
                            unitIsShutdown = true;
                            targetAppointment = p;

                            if (p.IsLinkedShutdownPlan == false)
                                continue;
                            else
                                break;
                        }
                    }

                    if (unitIsShutdown == true)
                    {
                        int numberOfDaysInCurrentMonth = DateTime.DaysInMonth(currentDay.Year, currentDay.Month);

                        DateTime firstDayOftheCurrentMonth = new DateTime(currentDay.Year, currentDay.Month, 1);
                        string key = getKeyForStringCapacity(oilString.UnitID, firstDayOftheCurrentMonth);

                        double stringCurrentDayCapacity = 0;
                        if (unitCapacityDictionary.ContainsKey(key))
                            stringCurrentDayCapacity = unitCapacityDictionary[key];

                        double loss = 0;
                        if (stringCurrentDayCapacity != 0)
                        {
                            if (rHelper.CapacityPercentage != 1)
                                loss = stringCurrentDayCapacity * (1 - rHelper.CapacityPercentage);
                            else
                                loss = stringCurrentDayCapacity;

                            if (targetAppointment != null)
                            {
                                LossByDivisionAndData l = new LossByDivisionAndData() { Loss = loss / numberOfDaysInCurrentMonth, Date = currentDay, Division = targetAppointment.Division, UnitName = targetAppointment.UnitName };
                                result.Add(l);
                            }
                        }
                    }
                }
            }
            return result;
        }
        #endregion

        #region Methods
        //leaf node means this unit is a tower and has only well as child
        private bool isLeafNode(Unit node)
        {
            bool isLeafNode = false;

            if (node.UnitType != FIFPConstants.UNITTYPE_TOWER)
            {
                isLeafNode = false;
            }
            else
            {
                if (hasPipelineAsChild(node))
                {
                    isLeafNode = false;
                }
                else
                {
                    isLeafNode = true;
                }
            }

            return isLeafNode;
        }

        private bool hasPipelineAsChild(Unit node)
        {
            bool hasPipelineAsChild = false;

            List<Unit> resultList = (from item in node.ChildUnitList
                                     where item.UnitType == FIFPConstants.UNITTYPE_PIPELINE
                                     select item).ToList<Unit>();

            if (resultList.Count != 0)
                hasPipelineAsChild = true;

            return hasPipelineAsChild;
        }

        private void setCurrentDayWellAndStringCapacity(Unit well, DateTime currentDay)
        {
            double wellCapacity = 0;
            foreach (Unit str in well.ChildUnitList)
            {
                double strCapacity = getCurrentDayStringCapacity(str, currentDay);
                str.Capacity = strCapacity;
                wellCapacity += strCapacity;
            }
            well.Capacity = wellCapacity;
        }

        private double getCurrentDayStringCapacity(Unit unit, DateTime currentDay)
        {
            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            DateTime firstDayOftheCurrentMonth = new DateTime(currentDay.Year, currentDay.Month, 1);
            string key = getKeyForStringCapacity(unit.UnitID, firstDayOftheCurrentMonth);
            //
            double stringCurrentDayCapacity = 0;
            if (unitCapacityDictionary.ContainsKey(key))
                stringCurrentDayCapacity = unitCapacityDictionary[key];
            if (isUnitShutdown(unit, currentDay, rHelper))
            {
                if (rHelper.CapacityPercentage != 1)
                    stringCurrentDayCapacity = stringCurrentDayCapacity * rHelper.CapacityPercentage;
                else if (rHelper.ReducedCapacity != 0)
                    stringCurrentDayCapacity = stringCurrentDayCapacity - rHelper.ReducedCapacity;
                else
                    stringCurrentDayCapacity = 0;
            }

            return stringCurrentDayCapacity;
        }

        private double getCurrentDayGasWellCapacity(Unit well, DateTime currentDay)
        {
            DateTime firstDayOftheCurrentYear = new DateTime(currentDay.Year, 1, 1);
            string key = getKeyForStringCapacity(well.UnitID, firstDayOftheCurrentYear);

            double gasWellCurrentDayCapacity = 0;
            if (unitCapacityDictionary.ContainsKey(key))
                gasWellCurrentDayCapacity = unitCapacityDictionary[key];

            ReducedCapacityHelper rHelper = new ReducedCapacityHelper();
            if (isUnitShutdown(well, currentDay, rHelper))
            {
                if (rHelper.CapacityPercentage != 1)
                    gasWellCurrentDayCapacity = gasWellCurrentDayCapacity * rHelper.CapacityPercentage;
                else
                    gasWellCurrentDayCapacity = 0;
            }

            return gasWellCurrentDayCapacity;
        }

        private bool isUnitShutdown(Unit unit, DateTime currentDay, ReducedCapacityHelper rHelper)
        {
            bool isUnitShutdown = false;

            if (unitShutdownPlanDictionary.ContainsKey(unit.UnitID))
            {
                List<FIFPAppointment> unitShutDownPlans = unitShutdownPlanDictionary[unit.UnitID];
                foreach (FIFPAppointment p in unitShutDownPlans)
                {
                    if (currentDay >= p.Start && currentDay <= p.End)
                    {
                        isUnitShutdown = true;
                        rHelper.CapacityPercentage = p.CapacityPercentage;
                        rHelper.ReducedCapacity = getCurrentDayUnitReducedCapacity(unit, currentDay);
                        return isUnitShutdown;
                    }
                }
            }
            return isUnitShutdown;
        }

        private double getCurrentDayUnitReducedCapacity(Unit unit, DateTime currentDay)
        {
            double reducedCapacity = 0;
            foreach (ReducedCapacity rc in ReducedCapacityList)
            {
                if (rc.UnitId == unit.UnitID)
                {
                    if (currentDay >= rc.StartDate && currentDay <= rc.EndDate)
                    {
                        if (rc.ReducedUnitCapacity > reducedCapacity)
                            reducedCapacity = rc.ReducedUnitCapacity;
                    }
                }

            }
            return reducedCapacity;
        }

        private string getKeyForStringCapacity(int sUID, DateTime currentDay)
        {
            return sUID.ToString() + currentDay.ToString("yyyyMMdd");
        }

        public Unit getUnitByUID(int uID)
        {
            List<Unit> uList = (from item in allUnitList
                                where item.UnitID == uID
                                select item).ToList<Unit>();
            if (uList.Count == 0)
                return null;
            else
                return uList[0];
        }

        private List<Unit> getChildWaterWells(Unit unit)
        {
            List<Unit> children = (from item in unit.ChildUnitList
                                   where item.UnitType == FIFPConstants.UNITTYPE_WELL && item.FluidType == FIFPConstants.FLUIDTYPE_WATER
                                   select item).ToList<Unit>();
            return children;
        }

        private List<Unit> getChildGasInjectionWells(Unit unit)
        {
            List<Unit> children = (from item in unit.ChildUnitList
                                   where item.UnitType == FIFPConstants.UNITTYPE_WELL && item.FluidType == FIFPConstants.FLUIDTYPE_GAS && item.ProdInjType == "I"
                                   select item).ToList<Unit>();
            return children;
        }

        private List<Unit> getChildOilWells(Unit unit)
        {
            List<Unit> children = (from item in unit.ChildUnitList
                                   where item.UnitType == FIFPConstants.UNITTYPE_WELL && item.FluidType == FIFPConstants.FLUIDTYPE_OIL
                                   select item).ToList<Unit>();
            return children;
        }

        private List<Unit> getChildWells(Unit unit)
        {
            List<Unit> children = (from item in unit.ChildUnitList
                                   where item.UnitType == FIFPConstants.UNITTYPE_WELL
                                   select item).ToList<Unit>();
            return children;
        }

        private List<Unit> getChildWithoutWells(Unit unit)
        {
            List<Unit> children = (from item in unit.ChildUnitList
                                   where item.UnitType != FIFPConstants.UNITTYPE_WELL
                                   select item).ToList<Unit>();
            return children;
        }

        private List<Unit> getOilRadials()
        {
            return (from item in allUnitList
                    where item.UnitType == FIFPConstants.UNITTYPE_RADIAL && item.FluidType == FIFPConstants.FLUIDTYPE_OIL
                    select item).ToList<Unit>();
        }
        #endregion

        #region Add activities to the corresponding units
        public void InitUnitShutdownDictionary(List<FIFPAppointment> importPlans)
        {
            foreach (FIFPAppointment appointment in importPlans)
            {
                if (unitShutdownPlanDictionary.ContainsKey(appointment.UnitID))
                {
                    List<FIFPAppointment> l = unitShutdownPlanDictionary[appointment.UnitID];
                    l.Add(appointment);
                }
                else
                {
                    List<FIFPAppointment> l = new List<FIFPAppointment>();
                    l.Add(appointment);
                    unitShutdownPlanDictionary.Add(appointment.UnitID, l);
                }
            }
        }
        #endregion
    }
}